package com.example.demo.utils;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
 * @author wolong
 */
public class TtsUtil {
    private final static Logger logger = LoggerFactory.getLogger(TtsUtil.class);
    private static final String PRE_PATH = "audio" + File.separator + "pre" + File.separator;
    public static final String AUDIO_PATH = "audio" + File.separator;
    private static final int SAMPLE_RATE = 30720;

    public static void main(String[] args) {
        /*
        ActiveXComponent sap = new ActiveXComponent("Sapi.SpVoice");
        // Dispatch是做什么的？
        Dispatch sapo = sap.getObject();
        try {

            // 音量 0-100
            sap.setProperty("Volume", new Variant(100));
            // 语音朗读速度 -10 到 +10
            sap.setProperty("Rate", new Variant(-2));

            Variant defalutVoice = sap.getProperty("Voice");

            Dispatch dispdefaultVoice = defalutVoice.toDispatch();
            Variant allVoices = Dispatch.call(sapo, "GetVoices");
            Dispatch dispVoices = allVoices.toDispatch();

            Dispatch setvoice = Dispatch.call(dispVoices, "Item", new Variant(1)).toDispatch();
            ActiveXComponent voiceActivex = new ActiveXComponent(dispdefaultVoice);
            ActiveXComponent setvoiceActivex = new ActiveXComponent(setvoice);

            Variant item = Dispatch.call(setvoiceActivex, "GetDescription");
            // 执行朗读。
            Dispatch.call(sapo, "Speak", new Variant("hello world! 你好啊，我是Heworld。"));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sapo.safeRelease();
            sap.safeRelease();
        }
        */
        //textToSpeech("this is my father");
    }

    public static void call(String text) {
        ActiveXComponent ax = null;
        try {
            ax = new ActiveXComponent("Sapi.SpVoice");

            // 运行时输出语音内容
            Dispatch spVoice = ax.getObject();
            // 音量 0-100
            ax.setProperty("Volume", new Variant(100));
            // 语音朗读速度 -10 到 +10
            ax.setProperty("Rate", new Variant(-2));
            // 执行朗读
            Dispatch.call(spVoice, "Speak", new Variant(text));

        } catch (Exception e) {
            logger.error("异常", e);
        }
    }

    public static void create(String fileName, String context) {
        long time1 = System.currentTimeMillis();
        tts(fileName, context);
        long time2 = System.currentTimeMillis();
        logger.info("生成" + fileName + " tts文件用时：" + (time2 - time1));
        format(fileName);
        long time3 = System.currentTimeMillis();
        logger.info(fileName + "转采样率用时：" + (time3 - time2));
    }

    public static boolean isAudioFileExist(String fileName) {
        String path = AUDIO_PATH + fileName + ".wav";
        return FileUtil.isExist(path);
    }

    public static void format(String fileName) {
        FileUtil.createDirectory(AUDIO_PATH);
        String filePath = PRE_PATH + fileName + ".wav";
        String targetPath = AUDIO_PATH + fileName + ".wav";
        File file = new File(filePath);
        File target = new File(targetPath);
        SystemUtil.formatSampleRate(file.getAbsolutePath(), target.getAbsolutePath(), SAMPLE_RATE);

        long start = System.currentTimeMillis();
        while (true) {
            if (target.length() > 0) {
                break;
            }
            //170Kb的文件，大约 170*10 ms，所以 大概除以128就行了
            long expireTime = file.length() >> 7;
            if (System.currentTimeMillis() - start > 10000) {
                throw new RuntimeException("转化失败");
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                logger.error("异常", e);
            }
        }
    }

    public synchronized static void tts(String fileName, String context) {
        FileUtil.createDirectory(PRE_PATH);
        String filePath = PRE_PATH + fileName + ".wav";

        ActiveXComponent svComponent = null;
        ActiveXComponent sfsComponent = null;
        ActiveXComponent safComponent = null;
        Dispatch spVoice = null;
        Dispatch spFileStream = null;
        Dispatch spAudioFormat = null;
        try {
            logger.info("标记点1");

            // 运行时输出语音内容
            svComponent = new ActiveXComponent("Sapi.SpVoice");
            logger.info("标记点2");
            spVoice = svComponent.getObject();
            // 下面是构建文件流把生成语音文件
            logger.info("标记点3");
            sfsComponent = new ActiveXComponent("Sapi.SpFileStream");
            logger.info("标记点4");
            spFileStream = sfsComponent.getObject();

            logger.info("标记点5");
            safComponent = new ActiveXComponent("Sapi.SpAudioFormat");
            logger.info("标记点6");
            spAudioFormat = safComponent.getObject();

            logger.info("标记点7");
            // 设置音频流格式
            Dispatch.put(spAudioFormat, "Type", new Variant(22));
            logger.info("标记点8");
            // 设置文件输出流格式
            Dispatch.putRef(spFileStream, "Format", spAudioFormat);
            logger.info("标记点9");
            // 调用输出 文件流打开方法，创建一个.wav文件
            Dispatch.call(spFileStream, "Open", new Variant(filePath), new Variant(3), new Variant(true));
            logger.info("标记点10");
            // 设置声音对象的音频输出流为输出文件对象
            Dispatch.putRef(spVoice, "AudioOutputStream", spFileStream);
            logger.info("标记点11");
            // 设置音量 0到100
            Dispatch.put(spVoice, "Volume", new Variant(100));
            logger.info("标记点12");
            // 设置朗读速度 -10 到 +10
            Dispatch.put(spVoice, "Rate", new Variant(-1));
            logger.info("标记点13");
            getVoices(spVoice);
            // 生成文件
            Dispatch.call(spVoice, "Speak", new Variant(context));
            logger.info("标记点14");

        } catch (Exception e) {
            logger.error("异常", e);
        } finally {
            // 关闭输出文件
            try {
                if (spFileStream != null) {
                    Dispatch.call(spFileStream, "Close");
                }
                if (spVoice != null) {
                    Dispatch.putRef(spVoice, "AudioOutputStream", null);
                }
                if (spAudioFormat != null) {
                    spAudioFormat.safeRelease();
                }
                if (spFileStream != null) {
                    spFileStream.safeRelease();
                }
                if (spVoice != null) {
                    spVoice.safeRelease();
                }

                if (safComponent != null) {
                    safComponent.safeRelease();
                }
                if (sfsComponent != null) {
                    sfsComponent.safeRelease();
                }
                if (svComponent != null) {
                    svComponent.safeRelease();
                }
            } catch (Exception e) {
                logger.error("异常", e);
            }
        }
    }

    public static String[] getVoices(Dispatch spVoice)
    {
        String[] voices=null;
        try
        {
            Dispatch voiceItems=Dispatch.call(spVoice,"GetVoices").toDispatch();
            int count=Integer.valueOf(Dispatch.call(voiceItems,"Count").toString());
            if(count > 0)
            {
                voices=new String[count];
                for(int i=0;i<count;i++)
                {
                    Dispatch voiceItem=Dispatch.call(voiceItems,"Item",new Variant(i)).toDispatch();
                    String voice=Dispatch.call(voiceItem,"GetDescription").toString();
                    System.out.println(voice);
                    voices[i]=voice;
                }
            }
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return voices;
    }
}
